package com.fizzgate.controller;

import com.fizzgate.config.AggregateRedisConfig;
import com.fizzgate.context.event.FizzRefreshEvent;
import com.fizzgate.dynamic.event.handle.NodeBizChangeConfig;
import com.fizzgate.service.PluginService;
import com.fizzgate.util.FIFOService;
import com.fizzgate.util.JacksonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

@Component
public class PluginServiceListener implements SmartApplicationListener {
    @Autowired
    private PluginService pluginService;
    @Autowired
    private FIFOService fifoService;

    private static final Logger LOGGER = LoggerFactory.getLogger(PluginServiceListener.class);
    @Value("${fizz-dynamic-biz-config.channel:fizz_dynamic_biz_config_channel}")
    private String channel;

    @Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
    private ReactiveStringRedisTemplate rt;
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
        return ApplicationReadyEvent.class.isAssignableFrom(eventType) || FizzRefreshEvent.class.isAssignableFrom(eventType);
    }

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        pluginService.postInit();

        onBizChange();
        fifoService.addTask(new Runnable() {
            @Override
            public void run() {
                List<Map> bizs = pluginService.getBizs();
                if (bizs != null) {
                    pluginService.downloadBizs(bizs);
                    pluginService.closeBizs(bizs);
                    pluginService.startBizs(bizs);
                }
            }
        });
    }

    private void onBizChange() {
        rt.listenToChannel(channel).doOnError(t -> {
            LOGGER.error("lsn {}", channel, t);
        }).doOnSubscribe(
                s -> {
                    LOGGER.info("success to lsn on {}", channel);
                }
        ).doOnNext(msg -> {
            String json = msg.getMessage();
            LOGGER.info("api config change: {}", json);
            try {
                fifoService.addTask(() -> {
                    NodeBizChangeConfig config = JacksonUtils.readValue(json, NodeBizChangeConfig.class);
                    if (config.force) {
                        // close biz and remove filename
                        if (config.filenames != null && !config.filenames.isEmpty())
                            config.filenames.forEach(filename->{
                                try {
                                    pluginService.closeAndRemoveBiz(filename);
                                }catch (RuntimeException e){
                                    LOGGER.error("failed to force to remove {}",filename);
                                }
                            });
                    }
                });

                fifoService.addTask(() -> {
                    List<Map> bizs = pluginService.getBizs();
                    pluginService.downloadBizs(bizs);
                    pluginService.closeBizs(bizs);
                    pluginService.startBizs(bizs);
                });
            } catch (Throwable t) {
                LOGGER.error("deser {}", json, t);
            }
        }).subscribe();
    }




}